package cn.shengchao.controler.ai;

import cn.hutool.core.util.StrUtil;
import cn.shengchao.examstar.ai.application.service.AIWorkflowApplicationService;
import cn.shengchao.examstar.ai.domain.repository.IAiChatFreeSunRepository;
import cn.shengchao.examstar.ai.domain.valueobject.SpecificationType;
import cn.shengchao.examstar.ai.domain.valueobject.UserId;
import cn.shengchao.examstar.ai.infrastructure.dao.po.AiSession;
import cn.shengchao.examstar.ai.infrastructure.external.ai.memory.AiChatMemoryService;
import cn.shengchao.examstar.ai.infrastructure.external.ai.prompt.CommentsPrompt;
import cn.shengchao.examstar.ai.infrastructure.external.ai.service.DifyChatflowClientService;
import cn.shengchao.examstar.ai.infrastructure.external.ai.util.AiClientUtil;
import cn.shengchao.examstar.ai.shared.enums.AiChatFreeType;
import cn.shengchao.examstar.ai.shared.enums.AiSessionTypeEnum;
import cn.shengchao.examstar.distribute.infrastrure.po.DistributeNodeInfo;
import cn.shengchao.examstar.distribute.infrastrure.service.DistributeNodeInfoService;
import cn.shengchao.examstar.rpc.distribute.enums.DistributeSaleRoleEnum;
import cn.shengchao.util.helper.LoginHelper;
import com.google.common.collect.Maps;
import io.swagger.v3.oas.annotations.Operation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import top.continew.starter.core.validation.CheckUtils;
import top.continew.starter.core.validation.ValidationUtils;
import top.continew.starter.log.annotation.Log;
import top.continew.starter.web.model.R;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY;
import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_RETRIEVE_SIZE_KEY;


@RestController
@Slf4j
@CrossOrigin("${project.cross-origin}")
@RequestMapping("/api/${project.version}/ai")
public class AiController {

    @Autowired
    private AiChatMemoryService aiChatMemoryService;

    @Autowired
    private AiClientUtil aiClientUtil;

    @Autowired
    private DifyChatflowClientService difyChatflowClientService;
    @Autowired
    private AIWorkflowApplicationService aiWorkflowApplicationService;
    @Autowired
    private DistributeNodeInfoService distributeNodeInfoService;
    @Autowired
    private IAiChatFreeSunRepository iAiChatFreeSunRepository;


    @GetMapping("/freeSum")
    public Map.Entry<String, Long> getFreeSum() {
        Long userId = LoginHelper.getUserId();
        DistributeNodeInfo distributeNodeInfo = distributeNodeInfoService.getDistributeNodeInfoInCode(userId,
                List.of(DistributeSaleRoleEnum.ROLE_MKMG, DistributeSaleRoleEnum.ROLE_DSPD, DistributeSaleRoleEnum.ROLE_SLMB));
        AiChatFreeType aiChatFreeType = AiChatFreeType.USER;
        if (distributeNodeInfo != null) {
            aiChatFreeType = AiChatFreeType.MEMBER;
        }
        return Maps.immutableEntry("freeSum", aiWorkflowApplicationService.getFreeSum(LoginHelper.getUserId(), aiChatFreeType));
    }


    //创建会话
    @RequestMapping("/session")
    public R createSession(@RequestParam(required = false) Long objectId, @RequestParam(required = false) Long subObjectId) {
        CheckUtils.throwIf(getFreeSum().getValue() <= 0, "免费次数不足");
        Long userId = LoginHelper.getUserId();
        AiSession aiSession = aiChatMemoryService.createSession(null, userId, AiSessionTypeEnum.COURSE_NODES.name(), objectId, subObjectId);
        return R.ok(Maps.immutableEntry("sessionId", aiSession.getConversationId()));
    }

    /**
     * 获取当前session对话
     */
    @RequestMapping("/session/{sessionId}/history")
    public R getHistorySession(@PathVariable String sessionId, @RequestParam(value = "size", required = false, defaultValue = "10") Integer size) {
        return R.ok(aiChatMemoryService.get(sessionId, size));
    }

    /**
     * 获取全部历史会话
     */
    @RequestMapping("/session/all/history")
    public R getHistorySession(@RequestParam(required = false) Long objectId, @RequestParam(required = false) Long subObjectId) {
        Long userId = LoginHelper.getUserId();
        return R.ok(aiChatMemoryService.getHistorySession(userId, objectId, subObjectId));
    }

    @Log(ignore = true)
    @Operation(hidden = true)
    @GetMapping(value = "session/{sessionId}/generateStream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> streamChat(@RequestParam String message,
                                   @PathVariable String sessionId) {
        ValidationUtils.throwIf(StrUtil.isBlank(message), "请输入问题");
        CheckUtils.throwIf(getFreeSum().getValue() <= 0, "免费次数不足");
        iAiChatFreeSunRepository.doAi(LoginHelper.getUserId(), 1L);
        ChatClient client = aiClientUtil.getChatClient();
        //定义系统角色
        ChatClient.ChatClientRequestSpec chatClientRequestSpec = client.prompt().system(CommentsPrompt.SYSTEM_AI_ROLE_PROMPT);
        //新建会话
        chatClientRequestSpec = chatClientRequestSpec.advisors(advisorSpec -> advisorSpec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, sessionId)
                .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 100));
        return chatClientRequestSpec
                .advisors(new MessageChatMemoryAdvisor(aiChatMemoryService))
                .user(message)
                .stream().content();
    }

    // ==================== Dify工作流相关API ====================

    /**
     * 创建Dify工作流会话
     */
    @GetMapping("/workflow/session")
    public R createWorkflowSession(@RequestParam String workflowId, @RequestParam String specificationTypeId) throws IOException {
        CheckUtils.throwIf(aiWorkflowApplicationService.getFreeSum(LoginHelper.getUserId(), AiChatFreeType.USER) <= 0, "免费次数不足");
        Long userId = LoginHelper.getUserId();
        Map<String, Object> params = new HashMap<>();

        // 使用应用服务获取类目和知识点信息
        String subject = aiWorkflowApplicationService.getHierarchicalSpecificationTypeName(
                SpecificationType.of(Long.parseLong(specificationTypeId)));

        String knowledge = aiWorkflowApplicationService.getKnowledgeLeafNodesAsJson(
                UserId.of(userId), SpecificationType.of(Long.parseLong(specificationTypeId)));
//        CheckUtils.throwIfEmpty(knowledge, "尚未提供知识点！");
        CheckUtils.throwIf("[]".equals(knowledge), "知识点更新中！请选择其他类目");
        params.put("subject", subject);
        params.put("knowledge", "");
        AiSession session = difyChatflowClientService.createWorkflowSession(userId, workflowId, params);
        return R.ok(Map.of("sessionId", session.getConversationId(), "message", (String) params.get("message")));
    }


    /**
     * 发送工作流消息（流式）
     */
    @Log(ignore = true)
    @Operation(hidden = true)
    @GetMapping(value = "/workflow/session/{conversationId}/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> sendWorkflowMessageStream(@PathVariable String conversationId,
                                                  @RequestParam String workflowId,
                                                  @RequestParam String specificationTypeId,
                                                  @RequestParam String message) {
        ValidationUtils.throwIf(StrUtil.isBlank(message), "请提供输入参数");
        CheckUtils.throwIf(getFreeSum().getValue() <= 0, "免费次数不足");

        Long userId = LoginHelper.getUserId();
        // 验证会话所有权
        CheckUtils.throwIf(!aiChatMemoryService.isSessionOwner(conversationId, userId), "无权访问该会话");
        iAiChatFreeSunRepository.doAi(userId, 1L);
        Map<String, Object> inputs = new HashMap<>();

        // 使用应用服务获取类目和知识点信息
        String subject = aiWorkflowApplicationService.getHierarchicalSpecificationTypeName(
                SpecificationType.of(Long.parseLong(specificationTypeId)));

//        String knowledge = aiWorkflowApplicationService.getKnowledgeLeafNodesAsJson(
//                UserId.of(userId), SpecificationType.of(Long.parseLong(specificationTypeId)));

        inputs.put("subject", subject);
        inputs.put("knowledge", "");

        return difyChatflowClientService.sendWorkflowMessageStream(conversationId, workflowId, inputs, message, String.valueOf(userId))
                .onErrorResume(throwable -> {
                    log.error("流式发送工作流消息失败: {}", throwable.getMessage(), throwable);
                    return Flux.just("data: {\"error\":\"" + throwable.getMessage() + "\"}");
                });
    }

}
